<!DOCTYPE html>
<html lang="zh-CN">

<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <meta name="robots" content="noodp" />
    <title class="pjax-title">081 Utilities - </title><meta name="Description" content=""><meta property="og:title" content="081 Utilities" />
<meta property="og:description" content="此文章记录lab1的实验过程与总结" />
<meta property="og:type" content="article" />
<meta property="og:url" content="http://gzhcoming.gitee.io/posts/081-utilities/" /><meta property="og:image" content="https://s2.loli.net/2022/02/23/W6mbADeS8uxr3Eq.png" /><meta property="article:section" content="posts" />
<meta property="article:published_time" content="2022-02-20T13:53:24+08:00" />
<meta property="article:modified_time" content="2022-02-20T13:53:24+08:00" />


<meta name="twitter:card" content="summary_large_image"/>
<meta name="twitter:image" content="https://s2.loli.net/2022/02/23/W6mbADeS8uxr3Eq.png"/>

<meta name="twitter:title" content="081 Utilities"/>
<meta name="twitter:description" content="此文章记录lab1的实验过程与总结"/>
<meta name="application-name" content="">
<meta name="apple-mobile-web-app-title" content="">

<meta name="theme-color" content="#f8f8f8"><link rel="shortcut icon" type="image/x-icon" href="/favicon.ico" />
        <link rel="icon" type="image/png" sizes="32x32" href="/favicon-32x32.png">
        <link rel="icon" type="image/png" sizes="16x16" href="/favicon-16x16.png"><link rel="apple-touch-icon" sizes="180x180" href="/apple-touch-icon.png"><link rel="canonical" href="http://gzhcoming.gitee.io/posts/081-utilities/" /><link rel="prev" href="http://gzhcoming.gitee.io/posts/create_blog/" /><link rel="next" href="http://gzhcoming.gitee.io/posts/%E8%B7%B3%E8%A1%A8skiplist/" /><link rel="stylesheet" href="/lib/normalize/normalize.min.css"><link rel="stylesheet" href="/css/style.min.css"><link rel="preload" as="style" onload="this.onload=null;this.rel='stylesheet'" href="/lib/fontawesome-free/all.min.css">
        <noscript><link rel="stylesheet" href="/lib/fontawesome-free/all.min.css"></noscript><link rel="preload" as="style" onload="this.onload=null;this.rel='stylesheet'" href="/lib/animate/animate.min.css">
        <noscript><link rel="stylesheet" href="/lib/animate/animate.min.css"></noscript><script type="application/ld+json">
    {
        "@context": "http://schema.org",
        "@type": "BlogPosting",
        "headline": "081 Utilities",
        "inLanguage": "zh-CN",
        "mainEntityOfPage": {
            "@type": "WebPage",
            "@id": "http:\/\/gzhcoming.gitee.io\/posts\/081-utilities\/"
        },"genre": "posts","wordcount":  3086 ,
        "url": "http:\/\/gzhcoming.gitee.io\/posts\/081-utilities\/","datePublished": "2022-02-20T13:53:24+08:00","dateModified": "2022-02-20T13:53:24+08:00","publisher": {
            "@type": "Organization",
            "name": "作者"},"author": {
                "@type": "Person",
                "name": "作者"
            },"description": ""
    }
    </script></head>

<body header-desktop="" header-mobile=""><script type="text/javascript">
        function setTheme(theme) {document.body.setAttribute('theme', theme);}
        function saveTheme(theme) {window.localStorage && localStorage.setItem('theme', theme);}
        function getMeta(metaName) {const metas = document.getElementsByTagName('meta'); for (let i = 0; i < metas.length; i++) if (metas[i].getAttribute('name') === metaName) return metas[i]; return '';}
        if (window.localStorage && localStorage.getItem('theme')) {let theme = localStorage.getItem('theme');theme === 'light' || theme === 'dark' || theme === 'black' ? setTheme(theme) : (window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches ? setTheme('dark') : setTheme('light')); } else { if ('' === 'light' || '' === 'dark' || '' === 'black') setTheme(''), saveTheme(''); else saveTheme('auto'), window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches ? setTheme('dark') : setTheme('light');}
        let metaColors = {'light': '#f8f8f8','dark': '#252627','black': '#000000'}
        getMeta('theme-color').content = metaColors[document.body.getAttribute('theme')];
    </script>
    <div id="back-to-top"></div>
    <div id="mask"></div><div class="wrapper"><header class="desktop" id="header-desktop">
    <div class="header-wrapper">
        <div class="header-title">
            <a href="/" title=""><span id="desktop-header-typeit" class="typeit"></span></a>
        </div>
        <div class="menu">
            <div class="menu-inner"><a class="menu-item" href="/posts/"> 文章 </a><a class="menu-item" href="/tags/"> 标签 </a><a class="menu-item" href="/series/"> 系列 </a><a class="menu-item" href="/about/"> 关于 </a><span class="menu-item delimiter"></span><a href="#" onclick="return false;" class="menu-item theme-switch" title="切换主题">
                    <i class="fas fa-adjust fa-fw"></i>
                </a></div>
        </div>
    </div>
</header><header class="mobile" id="header-mobile">
    <div class="header-container">
        <div class="header-wrapper">
            <div class="header-title">
                <a href="/" title=""><span id="mobile-header-typeit" class="typeit"></span></a>
            </div>
            <div class="menu-toggle" id="menu-toggle-mobile">
                <span></span><span></span><span></span>
            </div>
        </div>
        <div class="menu" id="menu-mobile"><a class="menu-item" href="/posts/" title="">文章</a><a class="menu-item" href="/tags/" title="">标签</a><a class="menu-item" href="/series/" title="">系列</a><a class="menu-item" href="/about/" title="">关于</a><a href="#" onclick="return false;" class="menu-item theme-switch" title="切换主题">
                <i class="fas fa-adjust fa-fw"></i>
            </a></div>
    </div>
</header>
<div class="search-dropdown desktop">
    <div id="search-dropdown-desktop"></div>
</div>
<div class="search-dropdown mobile">
    <div id="search-dropdown-mobile"></div>
</div>
<main class="main">
            <div class="container"><div class="toc" id="toc-auto">
        <h2 class="toc-title">目录</h2>
        <div class="toc-content" id="toc-content-auto"><nav id="TableOfContents">
  <ul>
    <li><a href="#一sleepeasy">一、sleep(Easy)</a>
      <ul>
        <li><a href="#要求">要求：</a></li>
        <li><a href="#思路">思路：</a></li>
        <li><a href="#代码">代码：</a></li>
      </ul>
    </li>
    <li><a href="#二pingpongeasy">二、pingpong(Easy)</a>
      <ul>
        <li><a href="#要求-1">要求：</a></li>
        <li><a href="#思路-1">思路：</a></li>
        <li><a href="#代码参考">代码参考：</a></li>
      </ul>
    </li>
    <li><a href="#三primes筛选素数hard">三、primes(筛选素数/Hard)</a>
      <ul>
        <li><a href="#要求-2">要求：</a></li>
        <li><a href="#思路-2">思路：</a></li>
        <li><a href="#代码参考-1">代码参考</a></li>
      </ul>
    </li>
    <li><a href="#四find中等">四、find(中等)</a>
      <ul>
        <li><a href="#要求-3">要求:</a></li>
        <li><a href="#思路-3">思路：</a></li>
        <li><a href="#参考代码">参考代码：</a></li>
      </ul>
    </li>
    <li><a href="#五xargshard">五、xargs(Hard！！)</a>
      <ul>
        <li><a href="#要求-4">要求:</a></li>
        <li><a href="#思路-4">思路：</a></li>
        <li><a href="#代码参考-2">代码参考：</a></li>
      </ul>
    </li>
    <li><a href="#最后附上通关的截图">最后附上通关的截图</a></li>
  </ul>
</nav></div>
    </div><script>document.getElementsByTagName("main")[0].setAttribute("pageStyle", "normal")</script><script>document.getElementsByTagName("main")[0].setAttribute("autoTOC", "true")</script><article class="page single"><h1 class="single-title animate__animated animate__flipInX">081 Utilities</h1><div class="post-meta">
            <div class="post-meta-line">
                <span class="post-author"><i class="author fas fa-user-circle fa-fw"></i><a href="/" title="Author" rel=" author" class="author">作者</a>
                </span>&nbsp;<span class="post-category">收录于 </span>&nbsp;<span class="post-series">系列 <a href="/series/mit-6.s081/"><i class="far fa-list-alt fa-fw"></i>mit 6.s081</a></span></div>
            <div class="post-meta-line"><i class="far fa-calendar-alt fa-fw"></i>&nbsp;<time datetime="2022-02-20">2022-02-20</time>&nbsp;<i class="far fa-edit fa-fw"></i>&nbsp;<time datetime="2022-02-20">2022-02-20</time>&nbsp;<i class="fas fa-pencil-alt fa-fw"></i>&nbsp;约 3086 字&nbsp;
                <i class="far fa-clock fa-fw"></i>&nbsp;预计阅读 7 分钟&nbsp;</div>
        </div><div class="details series-nav open">
                                <div class="details-summary series-title">
                                    <span>系列 - </span>
                                    <span><i class="details-icon fas fa-angle-right"></i></span>
                                </div>
                                <div class="details-content series-content">
                                    <nav>
                                        <ul><li><span class="active">081 Utilities</span></li></ul>
                                    </nav>
                                </div>
                            </div><div class="details toc" id="toc-static"  kept="">
                <div class="details-summary toc-title">
                    <span>目录</span>
                    <span><i class="details-icon fas fa-angle-right"></i></span>
                </div>
                <div class="details-content toc-content" id="toc-content-static"><nav id="TableOfContents">
  <ul>
    <li><a href="#一sleepeasy">一、sleep(Easy)</a>
      <ul>
        <li><a href="#要求">要求：</a></li>
        <li><a href="#思路">思路：</a></li>
        <li><a href="#代码">代码：</a></li>
      </ul>
    </li>
    <li><a href="#二pingpongeasy">二、pingpong(Easy)</a>
      <ul>
        <li><a href="#要求-1">要求：</a></li>
        <li><a href="#思路-1">思路：</a></li>
        <li><a href="#代码参考">代码参考：</a></li>
      </ul>
    </li>
    <li><a href="#三primes筛选素数hard">三、primes(筛选素数/Hard)</a>
      <ul>
        <li><a href="#要求-2">要求：</a></li>
        <li><a href="#思路-2">思路：</a></li>
        <li><a href="#代码参考-1">代码参考</a></li>
      </ul>
    </li>
    <li><a href="#四find中等">四、find(中等)</a>
      <ul>
        <li><a href="#要求-3">要求:</a></li>
        <li><a href="#思路-3">思路：</a></li>
        <li><a href="#参考代码">参考代码：</a></li>
      </ul>
    </li>
    <li><a href="#五xargshard">五、xargs(Hard！！)</a>
      <ul>
        <li><a href="#要求-4">要求:</a></li>
        <li><a href="#思路-4">思路：</a></li>
        <li><a href="#代码参考-2">代码参考：</a></li>
      </ul>
    </li>
    <li><a href="#最后附上通关的截图">最后附上通关的截图</a></li>
  </ul>
</nav></div>
            </div><div class="content" id="content"><p>实验文档：<a href="https://pdos.csail.mit.edu/6.S081/2020/labs/util.html" target="_blank" rel="noopener noreffer">Lab1: Xv6 and Unix utilities</a></p>
<p>本次实验要求实现5个小程序：</p>
<h2 id="一sleepeasy" class="headerLink">
    <a href="#%e4%b8%80sleepeasy" class="header-mark"></a>一、sleep(Easy)</h2><h3 id="要求" class="headerLink">
    <a href="#%e8%a6%81%e6%b1%82" class="header-mark"></a>要求：</h3><p>实现xv6的UNIX程序sleep：您的sleep应该暂停到用户指定的计时数。一个滴答(tick)是由xv6内核定义的时间概念，即来自定时器芯片的两个中断之间的时间。您的解决方案应该在文件user/sleep.c中</p>
<hr>
<h3 id="思路" class="headerLink">
    <a href="#%e6%80%9d%e8%b7%af" class="header-mark"></a>思路：</h3><p>该程序属于热身题，需要注意的地方有：<br>
1 需要判断sleep后面是否存在参数<br>
2 程序需要使用exit(0)来退出程序，而不是使用return<br>
3 使用该xv6系统提供的系统调用，该系统提供的函数user.h中</p>
<hr>
<h3 id="代码" class="headerLink">
    <a href="#%e4%bb%a3%e7%a0%81" class="header-mark"></a>代码：</h3><pre tabindex="0"><code>#include &#34;kernel/types.h&#34;
#include &#34;kernel/stat.h&#34;
#include &#34;user/user.h&#34;

#define STDIN_FILENO  0
#define STDOUT_FILENO 1
#define STDDER_FILENO 2

int main(int argc, char* argv[])
{
    if (argc != 2)
    {
        fprintf(STDDER_FILENO, &#34;usage: sleep &lt;number&gt;\n&#34;);
        exit(1);
    }
    int number = atoi(argv[1]);
    sleep(number);
    exit(0);
}
</code></pre><hr>
<h2 id="二pingpongeasy" class="headerLink">
    <a href="#%e4%ba%8cpingpongeasy" class="header-mark"></a>二、pingpong(Easy)</h2><h3 id="要求-1" class="headerLink">
    <a href="#%e8%a6%81%e6%b1%82-1" class="header-mark"></a>要求：</h3><p>编写一个使用UNIX系统调用的程序来在两个进程之间“ping-pong”一个字节，请使用两个管道，每个方向一个。父进程应该向子进程发送一个字节;子进程应该打印“<!-- raw HTML omitted -->: received ping”，其中<!-- raw HTML omitted -->是进程ID，并在管道中写入字节发送给父进程，然后退出;父级应该从读取从子进程而来的字节，打印“<!-- raw HTML omitted -->: received pong”，然后退出。您的解决方案应该在文件user/pingpong.c中。</p>
<hr>
<h3 id="思路-1" class="headerLink">
    <a href="#%e6%80%9d%e8%b7%af-1" class="header-mark"></a>思路：</h3><p>2.1 首先解释一下管道<br>
  管道是用于父子进程或有共同父亲关系进程之间的一种<strong>通讯机制</strong>，实际上，管道是由<strong>内核</strong>开辟的<strong>长度有限</strong>的缓存区。<br>
  在类Linux系统中，有一个概念是<strong>一切皆文件</strong>，因此，可以使用与读取文件同样的方法来操作管道，如read、write函数。需要注意的是，管道的读写是<strong>堵塞</strong>的，并且管道是半双工。</p>
<pre tabindex="0"><code>//p 用于存放管道两边的文件描述符
//0是读通道，1是写通道
int p[2];
//pipe函数参数接收一个数组
pipe(p);
</code></pre><p>2.2 pingpong<br>
  此程序没太大的难度，最关键的地方在于：需要创建两个管道，因此实验要求是需要父进程和子进程双向发送信息，从上诉对管道的描述，管道是半双工通信。<br>
  还要注意的是，对于write和read函数的使用方法即可。</p>
<hr>
<h3 id="代码参考" class="headerLink">
    <a href="#%e4%bb%a3%e7%a0%81%e5%8f%82%e8%80%83" class="header-mark"></a>代码参考：</h3><pre tabindex="0"><code>#include &#34;kernel/types.h&#34;
#include &#34;user.h&#34;

int main(int argc, char *argv[]) {
    int p_p[2]; //父写子读
    int p_s[2]; //子写父读

    pipe(p_p);
    pipe(p_s);

    int pid = fork();
    if( pid == 0) {
        //son
        close(p_p[1]);
        close(p_s[0]);
        char buf[1024];
        read(p_p[0], buf, sizeof(buf));
        printf(&#34;%d: received %s\n&#34;, getpid(), buf);
        write(p_s[1], &#34;pong&#34;, sizeof(&#34;pong&#34;));
        
    } else {
        //father
        close(p_s[1]);
        close(p_p[0]);
        char buf[1024];
        write(p_p[1], &#34;ping&#34;, sizeof(&#34;ping&#34;));
        read(p_s[0], buf, sizeof(buf));
        printf(&#34;%d: received %s\n&#34;, getpid(), buf);
    }
    exit(0);
}
</code></pre><hr>
<h2 id="三primes筛选素数hard" class="headerLink">
    <a href="#%e4%b8%89primes%e7%ad%9b%e9%80%89%e7%b4%a0%e6%95%b0hard" class="header-mark"></a>三、primes(筛选素数/Hard)</h2><h3 id="要求-2" class="headerLink">
    <a href="#%e8%a6%81%e6%b1%82-2" class="header-mark"></a>要求：</h3><p>使用管道编写prime sieve(筛选素数)的并发版本。</p>
<hr>
<h3 id="思路-2" class="headerLink">
    <a href="#%e6%80%9d%e8%b7%af-2" class="header-mark"></a>思路：</h3><p>  此程序在官方文档上标记是的是困难(但我觉得lab1中最难的并不是primes)。关于如何实现，可以参考<a href="https://swtch.com/~rsc/thread/" target="_blank" rel="noopener noreffer">Bell Labs and CSP Threads</a>这篇文章。<br>
  简单来说，这里使用的是最原始的方法，既暴力遍历，从2开始,每次对元素做取余运算，将符合条件的元素，推到管道里面，让下一个子进程来处理。由于，数据经过处理，可以知道管道中第一个元素肯定是素数(原因是：此元素对前面所有比它小的元素取余都由余数)。<br>
  此处比较坑的地方在于，xv6系统，只提供了15个文件描述符，因此需要即使close掉不再使用的文件描述符，来避免操作系统资源的限制。</p>
<hr>
<h3 id="代码参考-1" class="headerLink">
    <a href="#%e4%bb%a3%e7%a0%81%e5%8f%82%e8%80%83-1" class="header-mark"></a>代码参考</h3><pre tabindex="0"><code>#include &#34;kernel/types.h&#34;
#include &#34;kernel/stat.h&#34;
#include &#34;user/user.h&#34;
//int idx = 2;
void select(int idx, int pi[]) {
    close(pi[1]);
    int re;
    //从pi读第一个,如果读到的字符为0即递归结束
    if(read(pi[0], &amp;re, 4) == 0) {
        close(pi[0]);
        exit(0); 
    }// 一直等待管道读，知道写关闭
    //第一个肯定是素数,输出
    printf(&#34;prime %d\n&#34;, re);
    //创建新的管道, 用于把数据随送到子进程那里
    int child_pipe[2];
    int sum;
    pipe(child_pipe);
    //循环把读出的数据进行处理
    if( fork() == 0 ) {
        //son 进入递归循环
        close(pi[0]);
        close(child_pipe[1]);
        select(++idx, child_pipe);
    } else {
        //father
        //只要还能读出数据就继续处理
        while( read(pi[0], &amp;sum, 4)) {
            if(sum % idx != 0) {
                write(child_pipe[1], &amp;sum, 4);
            }
        }
        close(pi[0]);
        //全部数据处理完，关闭所有的管道
        close(child_pipe[0]);
        close(child_pipe[1]);
        wait((int*)0);
    }  
    exit(0);
}

int main(int argc, char *argv[]) {
    if(argc &gt; 1){          
		fprintf(2, &#34;Usage: primes\n&#34;);
		exit(1);
	}

    int p[2];
    pipe(p);

    int pid = fork();

    if( pid == 0) {
        //son
        for(int i = 2; i &lt; 35; ++i) {
            write(p[1], &amp;i, 4);   
        }
        close(p[1]);
        select(2, p);
    } else {
        //关闭父进程的读写管道
        close(p[0]);
        close(p[1]);
        wait((int*)0);
    }

    exit(0);
}
</code></pre><hr>
<h2 id="四find中等" class="headerLink">
    <a href="#%e5%9b%9bfind%e4%b8%ad%e7%ad%89" class="header-mark"></a>四、find(中等)</h2><h3 id="要求-3" class="headerLink">
    <a href="#%e8%a6%81%e6%b1%82-3" class="header-mark"></a>要求:</h3><p>写一个简化版本的UNIX的find程序：查找目录树中具有特定名称的所有文件.</p>
<hr>
<h3 id="思路-3" class="headerLink">
    <a href="#%e6%80%9d%e8%b7%af-3" class="header-mark"></a>思路：</h3><p>  由于find操作和ls操作类似，因此可以模仿ls函数加以改造即能完成find程序要求的功能。
4.1 首先来了解一下ls的代码</p>
<pre tabindex="0"><code>//可以留意到下面两个数据结构
struct dirent {
  ushort inum;//inum代表的是当前文件的目录项的个数
  char name[DIRSIZ]; //name是该文件的名字
};

#define T_DIR     1   // Directory
#define T_FILE    2   // File
#define T_DEVICE  3   // Device

struct stat {
  int dev;     // File system&#39;s disk device
  uint ino;    // Inode number
  short type;  // Type of file
  short nlink; // Number of links to file
  uint64 size; // Size of file in bytes
};

    在输出文件名字的时候，会使用到dirent结构体中的name，而在递归判断文件属性时，会使用到stat中的type属性。其余属性并不需要关注。
</code></pre><p>其次，ls中还可以参考的代码是展开目录时的操作</p>
<pre tabindex="0"><code>case T_DIR://展开目录
    if(strlen(path) + 1 + DIRSIZ + 1 &gt; sizeof buf){
      printf(&#34;ls: path too long\n&#34;);
      break;
    } //此处不需要关注，是ls结果显示时约束判定

    strcpy(buf, path);
    p = buf+strlen(buf);
    *p++ = &#39;/&#39;;
    //上面三行代码，是在当前文件路径后面加上&#39;/&#39;，如当前的文件路径是&#34;.&#34;，处理后的结果是&#34;./&#34;。

    //每次读取一个目录项，循环读取
    //目录也是文件，文件内容是该目录的目录项
    while(read(fd, &amp;de, sizeof(de)) == sizeof(de)){
        //inum代表的是该目录项下面的目录项数目
      if(de.inum == 0) 
        continue;
        //下面的操作是将目录项的名字拼接到文件路径中
        //如，&#34;./test&#34;
      memmove(p, de.name, DIRSIZ);
      p[DIRSIZ] = 0;
      if(stat(buf, &amp;st) &lt; 0){
        printf(&#34;ls: cannot stat %s\n&#34;, buf);
        continue;
      }
      printf(&#34;%s %d %d %d\n&#34;, fmtname(buf), st.type, st.ino, st.size);
    }
    break;
</code></pre><p>  最后需要注意的地方是，需要直接跳过处理&quot;.&quot;, &ldquo;..&ldquo;这两个目录项，否则会出现死循环。</p>
<hr>
<h3 id="参考代码" class="headerLink">
    <a href="#%e5%8f%82%e8%80%83%e4%bb%a3%e7%a0%81" class="header-mark"></a>参考代码：</h3><pre tabindex="0"><code>#include &#34;kernel/types.h&#34;
#include &#34;kernel/stat.h&#34;
#include &#34;user/user.h&#34;
#include &#34;kernel/fs.h&#34;

//char* name;
void check(char *path, char* name) {
    //static char buf[DIRSIZ+1];
    char *p;
    //从最后一位开始，寻找第一个 / 
    for(p=path+strlen(path); p &gt;= path &amp;&amp; *p != &#39;/&#39;; p--)
    ;
    p++;
    //判断该文件是否符合要求
    if(strcmp(p, name) == 0) {
        printf(&#34;%s\n&#34;, path);
    }
}
//只需要存在相同的名字，即把文件路径输出
void find(char * path, char* name) {
    char buf[512], *p;
    int fd;
    struct dirent de;
    struct stat st;
    //如果无法打开这个目录直接退出
    if((fd = open(path, 0)) &lt; 0){
        return;
    }
    if(fstat(fd, &amp;st) &lt; 0){
        close(fd);
        return;
    }
    switch(st.type) {
        //如果当前路径是文件，break
        //因为在目录时，已经将文件名字判断输出了
        case T_FILE: //正确
            //获取路径
            check(path, name);
        break;
        case T_DIR:
        //如果当前打开的是目录
        //把路径复制到buf数组里面
        //printf(&#34;test-- 这是一个目录\n&#34;);
        //把当前路径赋值给buf数组
        strcpy(buf, path);
        p = buf + strlen(buf);
        *p++ = &#39;/&#39;;
        //printf(&#34;%s\n&#34;, buf);
        while(read(fd, &amp;de, sizeof(de))) {
            //如果里面没有文件
            if(de.inum == 0) continue;
            //获取文件名
            memmove(p, de.name, DIRSIZ);
            //printf(&#34;%s\n&#34;, p);
            p[DIRSIZ] =0;
            //这里得到 ./目录下 每一个文件的文件名
           //如 ls cat文件 
            //如果文件名字为 . 和 .. 跳过，避免死循环
            if(strcmp(p, &#34;.&#34;) == 0) continue;
            if(strcmp(p, &#34;..&#34;) == 0) continue;
            find(buf, name);
        }
        break;
    }
    close(fd);
}

int main(int argc, char *argv[]) {
    //规定了输入的格式
    //1 目录树 2 文件名
    find(argv[1], argv[2]);
    exit(0);
}
</code></pre><hr>
<h2 id="五xargshard" class="headerLink">
    <a href="#%e4%ba%94xargshard" class="header-mark"></a>五、xargs(Hard！！)</h2><h3 id="要求-4" class="headerLink">
    <a href="#%e8%a6%81%e6%b1%82-4" class="header-mark"></a>要求:</h3><p>我认为这是五个程序里面最难得一个（x 编写一个简化版UNIX的xargs程序：它从标准输入中按行读取，并且为每一行执行一个命令，将行作为参数提供给命令。你的解决方案应该在user/xargs.c</p>
<hr>
<h3 id="思路-4" class="headerLink">
    <a href="#%e6%80%9d%e8%b7%af-4" class="header-mark"></a>思路：</h3><p>1 由于在命令行中输入，敲入回车键，即&rsquo;\n&rsquo;时，才会将该行数据推送到标准输入中。因此，可以直接认为，一次性把标准输入中得数据读完，这全部的数据都是同一行的输入，这样会大大减少判断每一行的复杂度。<br>
2 exec系统调用，会直接把当前进程的内存空间切换到需要执行的命令，因此，需要fork出一个子进程来处理exec来达循环调用exec。<br>
需要注意的是：exec参数中的二维数组，必须要以0结尾，而不是'0&rsquo;。如果写成'0&rsquo;，会直接error，血的教训。</p>
<hr>
<h3 id="代码参考-2" class="headerLink">
    <a href="#%e4%bb%a3%e7%a0%81%e5%8f%82%e8%80%83-2" class="header-mark"></a>代码参考：</h3><pre tabindex="0"><code>#include &#34;kernel/types.h&#34;
#include &#34;kernel/stat.h&#34;
#include &#34;user/user.h&#34;
#include &#34;kernel/fs.h&#34;
#include &#34;kernel/param.h&#34;

//char *arg = (char*) malloc(sizeof(line)); 

int main(int argc, char *argv[]) {
    
    // if( argc &lt; 2 ) {
    //     printf(&#34;enter more than 2 char&#34;);
    //     exit(0);
    // }

    //先把最先输出的参数获取
    char* op[MAXARG];
    int op_idx = 0;
    char* o= argv[1];
    
   
    for(int i = 1; i &lt; argc; ++i) {
        op[op_idx++] = argv[i];
    }

    char buf[1024];
    int n;
    while( (n = read(0, buf, 1024))  &gt; 0) {
        
        if( fork() == 0 ) {
            //son
            //son_op 是在buf中处理出来的 参数
            char* son_op =  (char*) malloc(sizeof(1024));
            int son_idx = 0;

            for(int i = 0; i &lt; n; i++) {
                if( buf[i] == &#39; &#39; || buf[i] == &#39;\n&#39;) {
                    son_op[son_idx] = 0;
                    op[op_idx++] = son_op;
                    //free(son_op);
                    son_op = (char*) malloc(sizeof(1024));
                    son_idx = 0;
                } else {
                    son_op[son_idx++] = buf[i];
                }
            }
            son_op[son_idx] = 0;
            op[op_idx] = 0;
            exec(o, op);
        } else {
            wait((int*)0);
        }
    }
    exit(0);
}
</code></pre><hr>
<h2 id="最后附上通关的截图" class="headerLink">
    <a href="#%e6%9c%80%e5%90%8e%e9%99%84%e4%b8%8a%e9%80%9a%e5%85%b3%e7%9a%84%e6%88%aa%e5%9b%be" class="header-mark"></a>最后附上通关的截图</h2><p><img
        class="lazyload"
        data-src="https://s2.loli.net/2022/02/20/4V2lDibG7Fhv9kj.png"
        data-srcset="https://s2.loli.net/2022/02/20/4V2lDibG7Fhv9kj.png, https://s2.loli.net/2022/02/20/4V2lDibG7Fhv9kj.png 1.5x, https://s2.loli.net/2022/02/20/4V2lDibG7Fhv9kj.png 2x"
        data-sizes="auto"
        alt="https://s2.loli.net/2022/02/20/4V2lDibG7Fhv9kj.png"
        title="lab1通关.png"></p>
</div>

        <div class="post-footer" id="post-footer">
    <div class="post-info">
        <div class="post-info-line">
            <div class="post-info-mod">
                <span>更新于 2022-02-20</span>
            </div>
            <div class="post-info-license"></div>
        </div>
        <div class="post-info-line">
            <div class="post-info-md"></div>
            <div class="post-info-share">
                <span><a href="#" onclick="return false;" title="分享到 Twitter" data-sharer="twitter" data-url="http://gzhcoming.gitee.io/posts/081-utilities/" data-title="081 Utilities"><i class="fab fa-twitter fa-fw"></i></a><a href="#" onclick="return false;" title="分享到 Facebook" data-sharer="facebook" data-url="http://gzhcoming.gitee.io/posts/081-utilities/"><i class="fab fa-facebook-square fa-fw"></i></a><a href="#" onclick="return false;" title="分享到 Hacker News" data-sharer="hackernews" data-url="http://gzhcoming.gitee.io/posts/081-utilities/" data-title="081 Utilities"><i class="fab fa-hacker-news fa-fw"></i></a><a href="#" onclick="return false;" title="分享到 Line" data-sharer="line" data-url="http://gzhcoming.gitee.io/posts/081-utilities/" data-title="081 Utilities"><i data-svg-src="/lib/simple-icons/icons/line.min.svg"></i></a><a href="#" onclick="return false;" title="分享到 微博" data-sharer="weibo" data-url="http://gzhcoming.gitee.io/posts/081-utilities/" data-title="081 Utilities"><i class="fab fa-weibo fa-fw"></i></a><a href="#" onclick="return false;" title="分享到 Telegram" data-sharer="telegram" data-url="http://gzhcoming.gitee.io/posts/081-utilities/" data-title="081 Utilities" data-web><i class="fab fa-telegram-plane fa-fw"></i></a></span>
            </div>
        </div>
    </div>

    <div class="post-info-more">
        <section class="post-tags"></section>
        <section>
            <span><a href="javascript:void(0);" onclick="window.history.back();">返回</a></span>&nbsp;|&nbsp;<span><a href="/">主页</a></span>
        </section>
    </div>

    <div class="post-nav"><a href="/posts/create_blog/" class="prev" rel="prev" title="Hugo搭建博客"><i class="fas fa-angle-left fa-fw"></i>Hugo搭建博客</a>
            <a href="/posts/%E8%B7%B3%E8%A1%A8skiplist/" class="next" rel="next" title="Skiplist">Skiplist<i class="fas fa-angle-right fa-fw"></i></a></div>
</div>
</article></div>
        </main><footer class="footer">
        <div class="footer-container"><div class="footer-line">
                    由 <a href="https://gohugo.io/" target="_blank" rel="noopener noreffer" title="Hugo 0.96.0">Hugo</a> 强力驱动&nbsp;|&nbsp;主题 - <a href="https://github.com/HEIGE-PCloud/DoIt" target="_blank" rel="noopener noreffer" title="DoIt 0.2.13"><i class="far fa-edit fa-fw"></i> DoIt</a>
                </div><div class="footer-line"><i class="far fa-copyright fa-fw"></i><span itemprop="copyrightYear">2022</span><span class="author" itemprop="copyrightHolder">&nbsp;<a href="/" target="_blank" rel="noopener noreferrer"></a></span></div>
            <div class="footer-line"></div>
            <div class="footer-line">
            </div>
        </div></footer></div>

    <div id="fixed-buttons"><a href="#back-to-top" id="back-to-top-button" class="fixed-button" title="回到顶部">
            <i class="fas fa-arrow-up fa-fw"></i>
        </a><a href="#" id="view-comments" class="fixed-button" title="查看评论">
            <i class="fas fa-comment fa-fw"></i>
        </a>
    </div><div class="assets"><script type="text/javascript" src="/lib/lazysizes/lazysizes.min.js"></script><script type="text/javascript" src="/lib/topbar/topbar.min.js"></script><script type="text/javascript" src="/lib/pjax/pjax.min.js"></script><script type="text/javascript" src="/js/theme.min.js"></script></div>

<div class="pjax-assets"><script type="text/javascript">window.config={"code":{"copyTitle":"复制到剪贴板","maxShownLines":10},"comment":{},"data":{"desktop-header-typeit":"Gzh's blog","mobile-header-typeit":"Gzh's blog"},"sharerjs":true,"typeit":{"cursorChar":null,"cursorSpeed":null,"data":{"desktop-header-typeit":["desktop-header-typeit"],"mobile-header-typeit":["mobile-header-typeit"]},"duration":null,"speed":null}};</script><script type="text/javascript" src="/lib/clipboard/clipboard.min.js"></script><script type="text/javascript" src="/lib/sharer/sharer.min.js"></script><script type="text/javascript" src="/lib/typeit/typeit.min.js"></script></div>
</body>

</html>